using System;
using System.Collections;
using System.Collections.Generic;

namespace IndiGoGameProcessor.Board
{
	#region Types
	
	public enum IntersectionState : byte
	{
		Empty = 0,
		White = 1,
		Black = 2,
	}
	
	#endregion
	
	public class Board : IEnumerable
	{	
		#region Declarations
		
		private List<List<IntersectionState>> _board;
		private readonly int _width;
		private readonly int _count;
		private IBoardEncoder _boardEncoder;
		
		#endregion
		
		public static bool operator ==(Board first, Board second)
		{
			return first.Encoded == second.Encoded;
		}
		
		public static bool operator !=(Board first, Board second)
		{
			return first.Encoded != second.Encoded;
		}
		
		public Board (int width)
		{
			_width = width;
			_count = width*width;
			_board = new List<List<IntersectionState>>();
			for(var y = 0; y < width; y++)
			{
				var test = IntersectionState.Empty;
				var row = new List<IntersectionState>();
				for(var x = 0; x < width; x++)
				{
					row.Add(test);
					switch(test)
					{
						case IntersectionState.Empty:
							test = IntersectionState.White;
							break;
						case IntersectionState.White:
							test = IntersectionState.Black;
							break;
						case IntersectionState.Black:
							test = IntersectionState.Empty;
							break;
					}
				}
				_board.Add(row);
			}
			_boardEncoder = new BoardEncoder();
		}
		
		public Board (List<byte> trits, int width) : this(width)
		{
			if(trits.Count < width*width) { throw new ArgumentException(); }
			
			_board = new List<List<IntersectionState>>();
			for(var y = 0; y < width; y++)
			{
				var row = new List<IntersectionState>();
				for(var x = 0; x < width; x++)
				{
					row.Add((IntersectionState)trits[x+y*width]);
				}
				_board.Add(row);
			}
		}
		
		public List<IntersectionState> this[int i]
		{
			get { return _board[i]; }
		}
		
		public int Count
		{
			get { return _count; }
		}
		
		public int Width
		{
			get { return _width; }
		}
		
		public int Height
		{
			get { return _width; }
		}
		
		public string Encoded
		{
			get { return _boardEncoder.EncodeBoard(this); }
		}
		
		public IEnumerator GetEnumerator ()
		{
			return new BoardEnumerator(this);
		}
		
		public class BoardEnumerator : IEnumerator
		{
			private Board _board;
			private int _row;
			private int _column;
			private int _width;
			
			internal BoardEnumerator(Board board)
			{
				_board = board;
				_width = board.Width;
				Reset ();
			}
			
			public object Current 
			{
				get
				{
					//return IntersectionState.Empty;
					return (object)(_board[_row][_column]);
				}
			}
	
			public bool MoveNext ()
			{
				_column++;
				if(_column >= _width)
				{
					_column = 0;
					_row ++;
				}
				return _row < _width;
			}
	
			public void Reset ()
			{
				_column = -1;
				_row = 0;
			}
	
			public void Dispose ()
			{
				_board = null;
			}
		}
	}
}

